﻿using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Net;
using Common;

namespace CommonTest
{
    [TestClass]
    public class IPAddressExtentionsTest
    {

        #region NetworkAddress Tests

        [TestMethod]
        public void FindIPv4NetworkAddress_Test_Standard_Class_C()
        {
            var ipAddress = IPAddress.Parse("192.168.1.1");
            var netmask = IPAddress.Parse("255.255.255.0");

            var expected = IPAddress.Parse("192.168.1.0");
            var actual = ipAddress.GetIPv4NetworkAddress(netmask);

            Assert.AreEqual(expected, actual);
        }
        
        [TestMethod]
        public void FindIPv4NetworkAddress_Test_Subnetted_Class_C()
        {
            var ipAddress = IPAddress.Parse("192.168.1.35");
            var netmask = IPAddress.Parse("255.255.255.224");

            var expected = IPAddress.Parse("192.168.1.32");
            var actual = ipAddress.GetIPv4NetworkAddress(netmask);

            Assert.AreEqual(expected, actual);
        }

        [TestMethod]
        public void FindIPv4NetworkAddress_Test_Standard_Class_B()
        {
            var ipAddress = IPAddress.Parse("172.16.2.56");
            var netmask = IPAddress.Parse("255.255.0.0");

            var expected = IPAddress.Parse("172.16.0.0");
            var actual = ipAddress.GetIPv4NetworkAddress(netmask);

            Assert.AreEqual(expected, actual);
        }

        [TestMethod]
        public void FindIPv4NetworkAddress_Test_Subnetted_Class_B()
        {
            var ipAddress = IPAddress.Parse("172.16.2.56");
            var netmask = IPAddress.Parse("255.255.254.0");

            var expected = IPAddress.Parse("172.16.2.0");
            var actual = ipAddress.GetIPv4NetworkAddress(netmask);

            Assert.AreEqual(expected, actual);
        }

        [TestMethod]
        public void FindIPv4NetworkAddress_Test_Standard_Class_A()
        {
            var ipAddress = IPAddress.Parse("10.0.0.1");
            var netmask = IPAddress.Parse("255.0.0.0");

            var expected = IPAddress.Parse("10.0.0.0");
            var actual = ipAddress.GetIPv4NetworkAddress(netmask);

            Assert.AreEqual(expected, actual);
        }

        [TestMethod]
        public void FindIPv4NetworkAddress_Test_Subnetted_Class_A()
        {
            var ipAddress = IPAddress.Parse("10.3.45.1");
            var netmask = IPAddress.Parse("255.254.0.0");

            var expected = IPAddress.Parse("10.2.0.0");
            var actual = ipAddress.GetIPv4NetworkAddress(netmask);

            Assert.AreEqual(expected, actual);
        }

        [TestMethod]
        public void FindIPv4NetworkAddress_Test_BadSubnetMask()
        {
            var ipAddress = IPAddress.Parse("5.5.5.5");
            var netmask = IPAddress.Parse("1.1.1.1");
            
            var actual = ipAddress.GetIPv4NetworkAddress(netmask);

            Assert.IsNull(actual);
        }

        [TestMethod]
        public void FindIPv4NetworkAddress_Test_IPv6Address()
        {
            var ipAddress = IPAddress.Parse("::1");
            var netmask = IPAddress.Parse("255.255.255.0");

            var actual = ipAddress.GetIPv4NetworkAddress(netmask);

            Assert.IsNull(actual);
        }


        #endregion NetworkAddress Tests

        #region BroadcastAddress Tests

        [TestMethod]
        public void FindIPv4BroadcastAddress_Test_Standard_Class_C()
        {
            var ipAddress = IPAddress.Parse("192.168.1.1");
            var netmask = IPAddress.Parse("255.255.255.0");

            var expected = IPAddress.Parse("192.168.1.255");
            var actual = ipAddress.GetIPv4BroadcastAddress(netmask);

            Assert.AreEqual(expected, actual);
        }

        [TestMethod]
        public void FindIPv4BroadcastAddress_Test_Subnetted_Class_C()
        {
            var ipAddress = IPAddress.Parse("192.168.1.35");
            var netmask = IPAddress.Parse("255.255.255.224");

            var expected = IPAddress.Parse("192.168.1.63");
            var actual = ipAddress.GetIPv4BroadcastAddress(netmask);

            Assert.AreEqual(expected, actual);
        }

        [TestMethod]
        public void FindIPv4BroadcastAddress_Test_Standard_Class_B()
        {
            var ipAddress = IPAddress.Parse("172.16.2.56");
            var netmask = IPAddress.Parse("255.255.0.0");

            var expected = IPAddress.Parse("172.16.255.255");
            var actual = ipAddress.GetIPv4BroadcastAddress(netmask);

            Assert.AreEqual(expected, actual);
        }

        [TestMethod]
        public void FindIPv4BroadcastAddress_Test_Subnetted_Class_B()
        {
            var ipAddress = IPAddress.Parse("172.16.2.56");
            var netmask = IPAddress.Parse("255.255.254.0");

            var expected = IPAddress.Parse("172.16.3.255");
            var actual = ipAddress.GetIPv4BroadcastAddress(netmask);

            Assert.AreEqual(expected, actual);
        }

        [TestMethod]
        public void FindIPv4BroadcastAddress_Test_Standard_Class_A()
        {
            var ipAddress = IPAddress.Parse("10.0.0.1");
            var netmask = IPAddress.Parse("255.0.0.0");

            var expected = IPAddress.Parse("10.255.255.255");
            var actual = ipAddress.GetIPv4BroadcastAddress(netmask);

            Assert.AreEqual(expected, actual);
        }

        [TestMethod]
        public void FindIPv4BroadcastAddress_Test_Subnetted_Class_A()
        {
            var ipAddress = IPAddress.Parse("10.3.45.1");
            var netmask = IPAddress.Parse("255.254.0.0");

            var expected = IPAddress.Parse("10.3.255.255");
            var actual = ipAddress.GetIPv4BroadcastAddress(netmask);

            Assert.AreEqual(expected, actual);
        }

        [TestMethod]
        public void FindIPv4BroadcastAddress_Test_BadSubnetMask()
        {
            var ipAddress = IPAddress.Parse("5.5.5.5");
            var netmask = IPAddress.Parse("1.1.1.1");

            var actual = ipAddress.GetIPv4BroadcastAddress(netmask);

            Assert.IsNull(actual);
        }

        [TestMethod]
        public void FindIPv4BroadcastAddress_Test_IPv6Address()
        {
            var ipAddress = IPAddress.Parse("::1");
            var netmask = IPAddress.Parse("255.255.255.0");

            var actual = ipAddress.GetIPv4BroadcastAddress(netmask);

            Assert.IsNull(actual);
        }

        #endregion BroadcastAddress Tests

        #region CompareIPv4Addresses Tests

        [TestMethod]
        public void CompareIPv4Addresses_Test_GreaterThan()
        {
            var ipAddress = IPAddress.Parse("192.168.1.5");
            var otherIpAddress = IPAddress.Parse("192.168.1.1");

            var actual = ipAddress.CompareIPv4Addresses(otherIpAddress);
            var expected = 1;

            Assert.AreEqual(expected, actual);
        }

        [TestMethod]
        public void CompareIPv4Addresses_Test_LessThan()
        {
            var ipAddress = IPAddress.Parse("192.168.1.1");
            var otherIpAddress = IPAddress.Parse("192.168.1.5");

            var actual = ipAddress.CompareIPv4Addresses(otherIpAddress);
            var expected = -1;

            Assert.AreEqual(expected, actual);
        }

        [TestMethod]
        public void CompareIPv4Addresses_Test_EqualTo()
        {
            var ipAddress = IPAddress.Parse("192.168.1.1");
            var otherIpAddress = IPAddress.Parse("192.168.1.1");

            var actual = ipAddress.CompareIPv4Addresses(otherIpAddress);
            var expected = 0;

            Assert.AreEqual(expected, actual);
        }

        #endregion CompareIPv4Addresses Tests

        #region IsIPv4NetMask Tests

        [TestMethod]
        public void IsIPv4Network_Test_ValidNetmask_0_bits()
        {
            var netmask = IPAddress.Parse("255.255.255.0");
            var actual = netmask.IsIPv4NetMask();

            Assert.IsTrue(actual);
        }

        [TestMethod]
        public void IsIPv4Network_Test_ValidNetmask_1_bit()
        {
            var netmask = IPAddress.Parse("255.255.255.128");
            var actual = netmask.IsIPv4NetMask();

            Assert.IsTrue(actual);
        }

        [TestMethod]
        public void IsIPv4Network_Test_ValidNetmask_2_bits()
        {
            var netmask = IPAddress.Parse("255.255.255.192");
            var actual = netmask.IsIPv4NetMask();

            Assert.IsTrue(actual);
        }

        [TestMethod]
        public void IsIPv4Network_Test_ValidNetmask_3_bits()
        {
            var netmask = IPAddress.Parse("255.255.255.224");
            var actual = netmask.IsIPv4NetMask();

            Assert.IsTrue(actual);
        }

        [TestMethod]
        public void IsIPv4Network_Test_ValidNetmask_4_bits()
        {
            var netmask = IPAddress.Parse("255.255.255.240");
            var actual = netmask.IsIPv4NetMask();

            Assert.IsTrue(actual);
        }

        [TestMethod]
        public void IsIPv4Network_Test_ValidNetmask_5_bits()
        {
            var netmask = IPAddress.Parse("255.255.255.248");
            var actual = netmask.IsIPv4NetMask();

            Assert.IsTrue(actual);
        }

        [TestMethod]
        public void IsIPv4Network_Test_ValidNetmask_6_bits()
        {
            var netmask = IPAddress.Parse("255.255.255.252");
            var actual = netmask.IsIPv4NetMask();

            Assert.IsTrue(actual);
        }

        [TestMethod]
        public void IsIPv4Network_Test_ValidNetmask_7_bits()
        {
            var netmask = IPAddress.Parse("255.255.255.254");
            var actual = netmask.IsIPv4NetMask();

            Assert.IsTrue(actual);
        }

        [TestMethod]
        public void IsIPv4Network_Test_ValidNetmask_8_bits()
        {
            var netmask = IPAddress.Parse("255.255.255.255");
            var actual = netmask.IsIPv4NetMask();

            Assert.IsTrue(actual);
        }

        [TestMethod]
        public void IsIPv4Network_Test_InvalidNetmask()
        {
            var netmask = IPAddress.Parse("255.252.255.0");
            var actual = netmask.IsIPv4NetMask();

            Assert.IsFalse(actual);
        }

        #endregion IsIPv4NetMask Tests

        #region GetNextIPv4Address Tests

        [TestMethod]
        public void GetNextIPv4Address_Test_StandardAddress()
        {
            var ipAddress = IPAddress.Parse("192.168.1.1");

            var actual = ipAddress.GetNextIPv4Address();
            var expected = IPAddress.Parse("192.168.1.2");

            Assert.AreEqual(expected, actual);
        }

        [TestMethod]
        public void GetNextIPv4Address_Test_ClassCTransition()
        {
            var ipAddress = IPAddress.Parse("192.168.1.255");

            var actual = ipAddress.GetNextIPv4Address();
            var expected = IPAddress.Parse("192.168.2.0");

            Assert.AreEqual(expected, actual);
        }

        [TestMethod]
        public void GetNextIPv4Address_Test_ClassBTransition()
        {
            var ipAddress = IPAddress.Parse("192.168.255.255");

            var actual = ipAddress.GetNextIPv4Address();
            var expected = IPAddress.Parse("192.169.0.0");

            Assert.AreEqual(expected, actual);
        }

        [TestMethod]
        public void GetNextIPv4Address_Test_ClassATransition()
        {
            var ipAddress = IPAddress.Parse("192.255.255.255");

            var actual = ipAddress.GetNextIPv4Address();
            var expected = IPAddress.Parse("193.0.0.0");

            Assert.AreEqual(expected, actual);
        }

        #endregion GetNextIPv4Address Tests

        #region GetAddressesInNetwork Tests

        [TestMethod]
        public void GetAddressesInNetwork_Test_Standard_Class_C()
        {
            var ipAddress = IPAddress.Parse("192.168.1.50");
            var netmask = IPAddress.Parse("255.255.255.0");

            var addressesInNetwork = ipAddress.GetAddressesInNetwork(netmask);

            Assert.AreEqual(254, addressesInNetwork.Count);
        }

        [TestMethod]
        public void GetAddressesInNetwork_Test_Subnetted_Class_C()
        {
            var ipAddress = IPAddress.Parse("192.168.1.50");
            var netmask = IPAddress.Parse("255.255.255.224");

            var addressesInNetwork = ipAddress.GetAddressesInNetwork(netmask);

            Assert.AreEqual(30, addressesInNetwork.Count);
        }

        [TestMethod]
        public void GetAddressesInNetwork_Test_Standard_Class_B()
        {
            var ipAddress = IPAddress.Parse("172.16.1.50");
            var netmask = IPAddress.Parse("255.255.0.0");

            var addressesInNetwork = ipAddress.GetAddressesInNetwork(netmask);

            Assert.AreEqual(65534, addressesInNetwork.Count);
        }

        [TestMethod]
        public void GetAddressesInNetwork_Test_Subnetted_Class_B()
        {
            var ipAddress = IPAddress.Parse("172.16.1.50");
            var netmask = IPAddress.Parse("255.255.254.0");

            var addressesInNetwork = ipAddress.GetAddressesInNetwork(netmask);

            Assert.AreEqual(510, addressesInNetwork.Count);
        }

        //Known bug with addresses by the millions 
        //I will look into this later.

        #endregion GetAddressesInNetwork Tests
    }
}
